package com.ho1ho.springboot.framework.core.utils;

import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

public class CipherManager {
//	public static void main(String[] args) {
////		String original = "あいうえお干什么你好吗";
//		String original = "password";
//		String enc = CipherManager.getInstance().encrypt(original);
////		String enc = "c00035446ab6c9289094eab737fadbfec7959e9a017137d1";
//		System.out.println("enc=" + enc);
//		String dec = CipherManager.getInstance().decrypt("3b61df580af237bf6de56a8197c27126");
//		System.out.println("dec=" + dec);
//	}
	
	/**
	 * 暗号化機能.
	 */
	private Cipher encrypt_ = null;
	
	/**
	 * 複合化機能.
	 */
	private Cipher decrypt_ = null;
	
	/**
	 * コンスラクタは非公開.
	 */
	private CipherManager() {
		// Keyの生成(推測されない文字)
		Key key = getKey("5a&9aG88S0bcv4-be3#!#@*_@!!0+8a6!@&@#39ec8f_0990.3149cb".getBytes());

		// DES方式
		try {
			this.encrypt_ = Cipher.getInstance("DES");
			this.encrypt_.init(Cipher.ENCRYPT_MODE, key);
			this.decrypt_ = Cipher.getInstance("DES");
			this.decrypt_.init(Cipher.DECRYPT_MODE, key);
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
			return;
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
			return;
		} catch (InvalidKeyException e) {
			e.printStackTrace();
			return;
		}
	}
	
	/**
	 * InstanceHolder.
	 */
	private static class InstanceHolder {
		private static final CipherManager instance = new CipherManager();
	}

	/**
	 * getInstance.
	 * 
	 * @return this instance.
	 */
	public static CipherManager getInstance() {
		return InstanceHolder.instance;
	}

	/**
	 * 暗号化します.
	 * @param aValue 暗号化対象の文字
	 * @return 暗号化された文字
	 */
	public String encrypt(String aValue) {
		String prefix = random(3);
		String postfix = random(3);
//		String value = PREFIX_SOLT + aValue + POSTFIX_SOLT;
		String value = prefix + aValue + postfix;
		try {
			String encode = byteArr2HexStr(encrypt(value.getBytes()));
			return encode;
		} catch (IllegalBlockSizeException e) {
			e.printStackTrace();
			return null;
		} catch (BadPaddingException e) {
			e.printStackTrace();
			return null;
		}
	}
	
	/**
	 * 複合化します.
	 * @param aValue 複合化対象の文字
	 * @return 複合化された文字
	 */
	public String decrypt(String aValue) {
		try {
			String value = new String(decrypt(hexStr2ByteArr(aValue)));
			String decode = value.substring(3, value.length() - 3);
			return decode;
		} catch (IllegalBlockSizeException e) {
			e.printStackTrace();
			return null;
		} catch (BadPaddingException e) {
			e.printStackTrace();
			return null;
		}
		
	}

	/**
	 * ランダムな値を生成します.
	 * @param aLength Specify length
	 * @return Random string
	 */
	public String random(int aLength) {
		String passTable = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
		return random(passTable, aLength);
	}

	/**
	 * Keyを生成します.
	 * @param aByte KeyParam
	 * @return key
	 */
	private Key getKey(byte[] aByte) {
		byte[] arrB = new byte[8];
		for (int i = 0; i < aByte.length && i < arrB.length; i++) {
			arrB[i] = aByte[i];
		}
		Key key = new javax.crypto.spec.SecretKeySpec(arrB, "DES");
		return key;
	}
	
	/**
	 * 暗号化します.
	 * @param aByte 暗号化対象byte
	 * @return 暗号化されたbyte
	 * @throws IllegalBlockSizeException Exception
	 * @throws BadPaddingException Exception
	 */
	private byte[] encrypt(byte[] aByte) throws IllegalBlockSizeException, BadPaddingException {
		return this.encrypt_.doFinal(aByte);
	}

	/**
	 * 複合化します.
	 * @param aByte 複合化対象byte
	 * @return 複合化されたbyte
	 * @throws IllegalBlockSizeException Exception
	 * @throws BadPaddingException Exception
	 */
	private byte[] decrypt(byte[] aByte) throws IllegalBlockSizeException, BadPaddingException {
		return this.decrypt_.doFinal(aByte);
	}

	/**
	 * ByteArrayの文字列変換.
	 * @param aByte
	 * @return hex string
	 */
	private String byteArr2HexStr(byte[] aByte) {
		int iLen = aByte.length;
		StringBuffer sb = new StringBuffer(iLen * 2);
		for (int i = 0; i < iLen; i++) {
			int intTmp = aByte[i];
			while (intTmp < 0) {
				intTmp = intTmp + 256;
			}
			if (intTmp < 16) {
				sb.append("0");
			}
			sb.append(Integer.toString(intTmp, 16));
		}
		return sb.toString();
	}

	/**
	 * 文字列のByteArray変換.
	 * @param aByte
	 * @return Byte array
	 */
	private byte[] hexStr2ByteArr(String aValue) {
		byte[] arrB = aValue.getBytes();
		int iLen = arrB.length;

		byte[] arrOut = new byte[iLen / 2];
		for (int i = 0; i < iLen; i = i + 2) {
			String strTmp = new String(arrB, i, 2);
			arrOut[i / 2] = (byte) Integer.parseInt(strTmp, 16);
		}
		return arrOut;
	}

	/**
	 * 指定条件にあったランダムな値を生成します.
	 * @param aTable 指定文字列
	 * @param aLength 結果長さ
	 * @return  ランダム値
	 */
	private String random(String aTable, int aLength) {
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < aLength; i++) {
			int rand = (int)(Math.random() * aTable.length());
			String one = aTable.substring(rand, rand+1);
			sb.append(one);
		}
		return sb.toString();
	}

}
